package mitlab.seg.ner.perceptron.model;

import mitlab.seg.ner.perceptron.feature.FeatureMap;
import mitlab.seg.ner.perceptron.instance.Instance;
import mitlab.seg.ner.perceptron.tagset.TagSet;

/**
 * 结构化感知机算法学习的线性模型
 *
 */
public class StructuredPerceptron extends LinearModel {
  public StructuredPerceptron(FeatureMap featureMap, float[] parameter) {
    super(featureMap, parameter);
  }

  public StructuredPerceptron(FeatureMap featureMap) {
    super(featureMap);
  }

  /**
   * 根据答案和预测更新参数
   *
   * @param goldIndex 答案的特征函数（非压缩形式）
   * @param predictIndex 预测的特征函数（非压缩形式）
   */
  public void update(int[] goldIndex, int[] predictIndex) {
    for (int i = 0; i < goldIndex.length; ++i) {
      if (goldIndex[i] == predictIndex[i])
        continue;
      else {
        parameter[goldIndex[i]]++;
        if (predictIndex[i] >= 0 && predictIndex[i] < parameter.length)
          parameter[predictIndex[i]]--;
        else {
          throw new IllegalArgumentException("更新参数时传入了非法的下标");
        }
      }
    }
  }

  public void update(Instance instance) {
    int[] guessLabel = new int[instance.length()];
    viterbiDecode(instance, guessLabel);
    TagSet tagSet = featureMap.tagSet;
    for (int i = 0; i < instance.length(); i++) {
      int[] featureVector = instance.getFeatureAt(i);
      int[] goldFeature = new int[featureVector.length];
      int[] predFeature = new int[featureVector.length];
      for (int j = 0; j < featureVector.length - 1; j++) {
        goldFeature[j] = featureVector[j] * tagSet.size() + instance.tagArray[i];
        predFeature[j] = featureVector[j] * tagSet.size() + guessLabel[i];
      }
      goldFeature[featureVector.length - 1] =
          (i == 0 ? tagSet.bosId() : instance.tagArray[i - 1]) * tagSet.size()
              + instance.tagArray[i];
      predFeature[featureVector.length - 1] =
          (i == 0 ? tagSet.bosId() : guessLabel[i - 1]) * tagSet.size() + guessLabel[i];
      update(goldFeature, predFeature);
    }
  }
}
